<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Hashtable</title>
    <style>
        div{
            margin-top:10px;
        }
        html {
            font-size:12px;
        }
    </style>
</head>
<body>
<div>
    <label for="capacity">capacity </label><input type="text" id="capacity" value="11" placeholder="请输入容量">
    <label for="factor">factor </label><input type="text" id="factor" value="0.75" placeholder="负载因子">
    <label for="fix">[fixed hashCode] </label><input type="text" id="fix" value="-1">
    <input type="button" value="init" id="initBtn">
</div>
<div>
    <label for="key">key </label><input type="text" id="key" placeholder="请输入key 以,分隔">
    <label for="codes">hashCode => </label><input type="text" readonly id="codes">
    <label for="indexes">[index] => </label><input type="text" readonly id="indexes">
</div>
<div>
    <input type="button" value="index" id="indexBtn">
    <input type="button" value="put" id="putBtn">
    <input type="button" value="remove" id="removeBtn">
    <input type="button" value="clear" id="clearBtn">

</div>
<div id="canvasDiv">
    <canvas id="canvas" width="1024" height="400"></canvas>
</div>
<script>
    document.getElementById("initBtn").onclick = function(){
        let capacity = document.getElementById("capacity").value;
        let factor = document.getElementById("factor").value;
        let url = `http://localhost:8080/v8/table/init?capacity=${capacity}&factor=${factor}`;
        fetch(url).then(r=>r.json()).then(json=>{
            loadData();
        });
    }
    document.getElementById("indexBtn").onclick = function(){
        let key = document.getElementById("key").value;
        let fix = document.getElementById("fix").value;
        let url = `http://localhost:8080/v8/table/index?key=${key}&fix=${fix}`;
        fetch(url).then(r=>r.json()).then(json=>{
            document.getElementById("codes").value=json.codes.join(",");
            document.getElementById("indexes").value=json.indexes.join(",");
        });
    }
    document.getElementById("clearBtn").onclick = function(){
        let url = `http://localhost:8080/v8/table/clear`;
        fetch(url).then(r=>r.json()).then(json=>{
            loadData();
        });
    }
    document.getElementById("removeBtn").onclick = function(){
        let key = document.getElementById("key").value;
        let fix = document.getElementById("fix").value;
        let url = `http://localhost:8080/v8/table/remove?key=${key}&fix=${fix}`;
        fetch(url).then(r=>r.json()).then(json=>{
            loadData();
        });
    }
    document.getElementById("putBtn").onclick = function(){
        let key = document.getElementById("key").value;
        let fix = document.getElementById("fix").value;
        let url = `http://localhost:8080/v8/table/put?key=${key}&fix=${fix}`;
        fetch(url).then(r=>r.json()).then(json=>{
            loadData();
        });
    }

    var Node = function (_data, _parent, _color) {
        this.data = _data;
        this.parent = _parent;
        this.color = _color;
        this.left = null;
        this.right = null;
    }

    let canvas = document.getElementById("canvas");
    let ctx = canvas.getContext("2d");

    function loadData() {
        let bWidth = 18;
        let bHeight = 15;
        let xBegin = 0;
        let yBegin = 0;
        let tableCells = [];
        fetch("http://localhost:8080/v8/table/tree").then(r=>r.json()).then(data=>{
            let length = data.buckets.length;
            canvas.width = xBegin + (length*(bWidth + 2));
            for(let i = 0; i < length; i++) {
                let x = xBegin + i*(bWidth + 2);
                let y = yBegin ;
                tableCells.push({x, yBegin});
                ctx.fillStyle="yellow";
                ctx.fillRect(x,yBegin,bWidth,bHeight);

                ctx.fillStyle="black";
                //ctx.font="14px Georgia";
                ctx.font = "bold 12px Arial";
                ctx.fillText(i,x+bWidth/2-5,y+bHeight/2+4);
            }

            for(let i = 0; i < length; i++) {
                let x = tableCells[i].x;
                let node = data.buckets[i];
                if("list"==node.type){
                    for(let j=0; j<node.value.length; j++){
                        let y;
                        if(j==0) {
                            y = yBegin + bHeight + 2;
                        } else {
                            y = yBegin + bHeight + 2 + j*bHeight*2;
                        }
                        //ctx.fillStyle="LightBlue";
                        //ctx.fillRect(x,y,bWidth,bHeight);
                        ctx.beginPath();
                        ctx.fillStyle = "green";
                        ctx.arc(x+pointSize, y+pointSize, pointSize, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false);
                        ctx.fill();
                        ctx.closePath();

                        //ctx.fillStyle="black";
                        //ctx.font="14px Georgia";
                        ctx.fillStyle = "white";
                        ctx.font = "bold 10px Arial";
                        ctx.fillText(node.value[j],x+bWidth/2-5,y+bHeight/2+4);

                        ctx.moveTo(x+bWidth/2, y+bHeight);
                        ctx.lineTo(x+bWidth/2, y+bHeight);
                        ctx.lineTo(x+bWidth/2, y+bHeight*2);
                        ctx.stroke();
                    }
                } else if("tree"==node.type){
                    let map = new Map();
                    for(let j=0; j<node.value.length; j++){
                        let v = node.value[j];
                        map.set(v.data, new Node(v.data, null, v.color));
                    }
                    let root = null;
                    for(let j=0; j<node.value.length; j++){
                        let v = node.value[j];
                        let n = map.get(v.data);
                        if(j == 0){
                            root = n;
                        }
                        n.left = map.get(v.left) || null;
                        n.right = map.get(v.right) || null;
                        n.parent = map.get(v.parent) || null;
                    }
                    SetPoint(root);
                    PreOrder(root, SetPreOrder, ctx, x+9);
                }
            }
        });
    }
    loadData();


    var pointSize = 8;
    var height = pointSize*4;//节点之间的高
    var width = pointSize;//节点之间的宽
    var tops = 25;//根节点离顶部的距离
    var foot = 40;//树离底部距离
    var spacing = 30;//树分别离两边的间距

    //let root = new Node("a",null,"black");
    //root.left = new Node("b",root,"red");
    //root.right = new Node("c",root,"red");
    //root.left.left = new Node("d",root.left,"black");
    //root.left.right = new Node("e",root.left,"black");
    //root.right.left = new Node("f",root.right,"red");
    //root.right.right = new Node("g",root.right,"red");
    //SetPoint(root);
    //PreOrder(root, SetPreOrder, ctx, canvas.width);

    function PreOrder(node, action, context, startX) {
        action(node, context, startX);
        if (node.left != null) {
            PreOrder(node.left, action, context, startX);
        }

        if (node.right != null) {
            PreOrder(node.right, action, context, startX);
        }
    }


    function SetCanvasWidthHeight(rootNode) {
        var level = Level(rootNode);
        return {
            height: height * level + tops + foot,
            width: Math.pow(2, level + 1) * width + spacing * 2
        };
    }

    function SetPreOrder(node, context, startX) {
        var container = drawArc(
            context,
            node.data,
            startX + width * node.nodePoint,
            (node.nodeLevel * height + parseInt(tops)),
            node.color);

        if (node.parent != null) {
            var line = linkNode(
                context,
                (startX + width * node.parent.nodePoint),
                (node.parent.nodeLevel * height + parseInt(tops)),
                (node.data, startX + width * node.nodePoint),
                (node.nodeLevel * height + parseInt(tops)));
        }
    }

    //生产节点
    function drawArc(context, number, x, y, color) {
        //圆
        context.beginPath();
        context.fillStyle = color;
        context.arc(x, y, pointSize, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false);
        context.fill();
        context.closePath();

        //数字
        var textX = x - 3;
        var textY = y + 5;
        /*if (number < 10) {
            textX -= 5;
        } else if (number > 9 && number < 100) {
            textX -= 8;
        } else {
            textX -= 12;
        }*/

        context.fillStyle = "white";
        context.font = "bold 13px Arial";
        context.fillText(number + "", textX, textY);
    }

    //链接节点
    function linkNode(context, fatherNodeX, fatherNodeY, childrenNodeX, childrenNodeY) {
        drawLine(context, fatherNodeX, fatherNodeY + pointSize, childrenNodeX, childrenNodeY - pointSize);
    }

    //生产线
    function drawLine(context, x, y, toX, toY) {
        context.moveTo(x, y);
        context.lineTo(x, y);
        context.lineTo(toX, toY);
        context.stroke();
    }
    var maxLevel;
    var level;
    function Level(rootNode) {
        maxLevel = 0;
        level = 0;
        return levels(rootNode);
    }

    function levels(node) {
        if (node.left != null) {
            level++;
            levels(node.left);
        }
        maxLevel = Math.max(maxLevel, level);

        if (node.right != null) {
            level++;
            levels(node.right);
        }
        level--;
        return maxLevel;
    }

    function SetPoint(rootNode) {
        var thisMaxLevel = Level(rootNode);
        var childQuanty = Math.pow(2, thisMaxLevel);

        rootNode.nodeLevel = 0;
        rootNode.nodePoint = 0;

        if (rootNode.left != null) {
            setPointsLeft(rootNode.left, -1 * childQuanty / 2, 0, thisMaxLevel - 1);
        }

        if (rootNode.right != null) {
            setPointsRight(rootNode.right, childQuanty / 2, 0, thisMaxLevel - 1);
        }
    }

    function setPointsLeft(node, point, levels, thisMaxLevel) {
        ++levels;
        node.nodeLevel = levels;
        node.nodePoint = point;

        if (node.left != null) {
            setPointsLeft(node.left, point - Math.pow(2, thisMaxLevel - levels), levels, thisMaxLevel);
        }

        if (node.right != null) {
            setPointsLeft(node.right, point + Math.pow(2, thisMaxLevel - levels), levels, thisMaxLevel);
        }
    }

    function setPointsRight(node, point, levels, thisMaxLevel) {
        ++levels;
        node.nodeLevel = levels;
        node.nodePoint = point;

        if (node.left != null) {
            setPointsRight(node.left, point - Math.pow(2, thisMaxLevel - levels), levels, thisMaxLevel);
        }

        if (node.right != null) {
            setPointsRight(node.right, point + Math.pow(2, thisMaxLevel - levels), levels, thisMaxLevel);
        }
    }
</script>
</body>
</html>